<template>
  <div ref="map" class="map"></div>
</template>

<script setup>
import {
  flatCoordinates,
  getGeoJSON,
  createScene,
  createBufferGeometry,
} from "@/utils/geojsonUtil.js";
import { ref, onMounted } from "vue";
import { extrudePolygons } from "poly-extrude";
import * as THREE from "three";
import * as BufferGeometryUtil from "three/examples/jsm/utils/BufferGeometryUtils";
import { center as turfCenter, toMercator } from "@turf/turf";

const map = ref("");

const getBuildInfo = (tags) => {
  let height = Math.random() * 20;
  const arr = tags.split(",");
  const build = arr.find((s) => s.startsWith('"building:levels"'));
  if (build) {
    let h = build.split("=>")[1];
    if (h) {
      h = h.replaceAll('"', "");
      if (!Number.isNaN(Number(h))) {
        height = Number(h);
      }
    }
  }
  return height;
};

onMounted(() => {
  const fragmentShader = `
#include <common>
 
uniform vec3 iResolution;
uniform float iTime;
 
// 通过 iq：https://www.shadertoy.com/user/iq  
// 许可证：Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License。

#define green vec3(0.0,1.0,0.0)

// returns a vec3 color from every pixel requested.
// Generates a BnW Ping on normalized 2d coordinate system
vec3 RadarPing(in vec2 uv, in vec2 center, in float innerTail, 
               in float frontierBorder, in float timeResetSeconds, 
               in float radarPingSpeed, in float fadeDistance)
{
    vec2 diff = center-uv;
    float r = length(diff);
    float time = mod(iTime, timeResetSeconds) * radarPingSpeed;
   
    float circle;
    // r is the distance to the center.
    // circle = BipCenter---//---innerTail---time---frontierBorder
    //illustration
    //https://sketch.io/render/sk-14b54f90080084bad1602f81cadd4d07.jpeg
    circle += smoothstep(time - innerTail, time, r) * smoothstep(time + frontierBorder,time, r);
	circle *= smoothstep(fadeDistance, 0.0, r); // fade to 0 after fadeDistance
        
    return vec3(circle);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
  //normalize coordinates 
    vec2 uv = fragCoord.xy / iResolution.xy; //move coordinates to 0..1
    uv = uv.xy*2.; // translate to the center
    uv += vec2(-1.0, -1.0);
    uv.x *= iResolution.x/iResolution.y; //correct the aspect ratio
    
	  vec3 color;
    // generate some radar pings
    float fadeDistance = 1.0;
    float resetTimeSec = 4.0;
    float radarPingSpeed = 0.3;
    vec2 greenPing = vec2(0.0, 0.0);
    color += RadarPing(uv, greenPing, 0.25, 0.025, resetTimeSec, radarPingSpeed, fadeDistance) * green;
    
    //return the new color
	  fragColor = vec4(color,1.0);
}
 
void main() {
  mainImage(gl_FragColor, gl_FragCoord.xy);
}
`;

  const uniforms = {
    iTime: { value: 0 },
    iResolution: { value: new THREE.Vector3() },
  };

  const { scene } = createScene(map.value, (scene, camera, render, timer) => {
    const canvas = render.domElement;
    uniforms.iResolution.value.set(canvas.width, canvas.height, 1);
    uniforms.iTime.value = timer * 0.001;
  });

  // const material = new THREE.MeshPhongMaterial({ color: "#fff" });
  const material = new THREE.ShaderMaterial({
    fragmentShader,
    uniforms,
  });

  getGeoJSON("./wuhan.geojson").then((json) => {
    const geometries = [];
    json.features = json.features.slice(0, 10000);
    json = toMercator(json);
    flatCoordinates(json);

    json.features
      .filter((feature) => feature.properties.building === "yes")
      .forEach((feature) => {
        const { type, coordinates } = feature.geometry;
        let height = getBuildInfo(feature.properties.other_tags || "");

        const result = extrudePolygons(
          type === "Polygon" ? [coordinates] : coordinates,
          { depth: height }
        );
        const geometry = createBufferGeometry(result);
        geometries.push(geometry);
      });

    const mergeGeo = BufferGeometryUtil.mergeBufferGeometries(
      geometries,
      false
    );
    const mesh = new THREE.Mesh(mergeGeo, material);
    scene.add(mesh);
  });
});
</script>

<style scoped>
.map {
  width: 100%;
  height: 100%;
}
</style>
